import MQTT from 'mqtt'
import { config } from '@/config'
import { getUser, sleep } from './util'

type CallBack = (id: string, data: Record<string, any>) => void
type Type = 'user' | 'share' | 'company' | 'message' | 'public'

export class MqttClient {
    private static client: MQTT.MqttClient
    private static status: string
    private static callbacks: Record<string, CallBack> = {}
    private static checking = false

    private static async check() {
        if (MqttClient.checking) {
            await sleep(500)
            await MqttClient.check()
            return
        }
        MqttClient.checking = true
        if (!MqttClient.client) {
            const user = await getUser()
            const username = user?.userid || '-1'
            MqttClient.client = MQTT.connect(config.mqtt, {
                username,
            })
            MqttClient.client.on('connect', () => {
                MqttClient.status = 'connected'
                MqttClient.checking = false
            })
            MqttClient.client.on('close', () => {
                MqttClient.status = 'closed'
                MqttClient.checking = false
            })
            MqttClient.client.on('offline', () => {
                MqttClient.status = 'offline'
                MqttClient.checking = false
            })
            MqttClient.client.on('error', (e) => {
                console.error(e)
                MqttClient.checking = false
            })
            MqttClient.client.on('message', MqttClient.take)
        } else {
            if (MqttClient.status !== 'connected' && MqttClient.status !== 'reconnect') {
                MqttClient.client.reconnect()
            }
            MqttClient.checking = false
        }
    }

    private static take(_: string, message: string) {
        try {
            const { id, data } = JSON.parse(message)
            console.log('新消息：', _, JSON.stringify({ id, data }))
            if (MqttClient.callbacks[id]) {
                MqttClient.callbacks[id](id, data)
            }
        } catch (e) {
            console.log(e)
        }
    }

    static subscribe(type: Type, id: string, callback: CallBack = () => {}) {
        MqttClient.check().then(() => {
            if (type === 'message') {
                MqttClient.callbacks[id] = callback
            } else {
                MqttClient.client?.subscribe(`${type}:${id}`)
            }
        })
    }
    static publish(type: Type, id: string, message: string) {
        MqttClient.check().then(() => {
            MqttClient.client?.publish(`${type}:${id}`, message)
        })
    }
    static unsubscribe(type: Type, id: string) {
        MqttClient.client?.unsubscribe(`${type}:${id}`)
    }
}
